/*
 * Mailer.cpp
 *
 *  Created on: 14/06/2009
 *      Author: banouz
 */

#include "Mailer.h"
#include "RRscheduler.h"
#include "MLscheduler.h"
#include "SRTFscheduler.h"

/* Declaration of the wrapper function */
extern "C"
{
	void *wrapper(void *args)
	{
		Mailer *curThread = (Mailer *)args;
		curThread->run();
		return NULL;
	}
}

 // pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
  pthread_cond_t  condition_cond  = PTHREAD_COND_INITIALIZER;

Mailer::Mailer()
{

}

Mailer::~Mailer()
{

}


Mailer::Mailer(map<string, Worker> &mailMapWork,map<string, vector<string> > &graph,
    map<int, string> &idMap)
{
  _mailMapWork = &mailMapWork;
  _graph = &graph;
  _idMap = &idMap;
  _isFull = false;
  _exit = false;

    map<string, Worker>::iterator it; //Eran
      for (it = _mailMapWork->begin(); it != _mailMapWork->end(); ++it) {
          it->second.setOutMailerMBoxRef(_outMBox);
          it->second.setInMailerMBoxRef(_inMBox);
      }
}
//Search if there any new message to treat
void Mailer:: sendNewMess(){

}



void Mailer::run(){
	sleep(2);

	setScheduler(_scheduler_num);


	// start running the workers //

	map<string, Worker>::iterator it2;

	          for(it2 = _mailMapWork->begin(); it2 != _mailMapWork->end() ; it2++){
	       	  it2->second.start();
	          }

	MyMessage* current_msg;
	sleep(4);
	while(!_exit){

		if (!_outMBox.empty()){
			pthread_mutex_lock(&condition_mutex);
			current_msg = _outMBox.top();

			map<string,vector<string> > rt;
			 map<string, vector<string> > t = current_msg->getRt();
			MyMessage *tMyMes= new MyMessage(current_msg->getTo(),current_msg->getFrom(),current_msg->getType(),
					current_msg->getRegMess(), &t);

			_outMBox.pop();

////			in case of not killed or message = revive :
//
//					1. text - treMsg
//					2.  message = killNode/reviveNode ==> stable the system  (the need of DVR)
//					3. revive - change workers state to revived.(3)
////				4. other - push to out box


			//if ((!m_workerVector[msg->getDest()-1]->getKilled()) | (msg->getType() == ReviveMsg))
			bool isKilledt;
			isKilledt = false;
			map<string,Worker >::iterator WorkerIt = _mailMapWork->find(current_msg->getTo());

			if( WorkerIt != _mailMapWork->end() ){
			        isKilledt = WorkerIt->second.getIsKilled();
			 }

			if( (!isKilledt) | (current_msg->getType() ==  3) ){

					if(current_msg->getType()== 2 || current_msg->getType()== 3){
						cout<<" kill or revive msg " << endl;
						sleep(2);
						//stable state...
					}
					if(current_msg->getType()== 3){
						cout<<" Revive message " << endl;
						sleep(4);
						map<string,Worker >::iterator WorkerIt = _mailMapWork->find(current_msg->getTo());
						WorkerIt->second.setNotKilled();
					}
					else{
						map<string, Worker>::iterator WorkerIt = _mailMapWork->find(current_msg->getTo());
						sleep(1);
						WorkerIt->second.pushIntoInBox(tMyMes);
						sleep(1);
						WorkerIt->second.wakeOutOfMess();
						cout<<" RT message      " << _outMBox.size() << endl;

					}

					pthread_mutex_unlock(&condition_mutex);
			}else {

					delete(current_msg);
					pthread_mutex_unlock(&condition_mutex);

				   }
		}

		sleep(3);
			_scheduler->nextWorker();

			if(_scheduler->isStable()){
				//_scheduler->printSum();
				//_exit = true;
			}

			if (_exit) {
					map<string, Worker>::iterator it;
					for(it = _mailMapWork->begin(); it != _mailMapWork->end() ; it++){
					}
			}


	}

}

void Mailer::start(int sc_num,int quanta){
		pthread_create(&_mailer_thread, NULL,wrapper, this);
		_scheduler_num = sc_num;
		_quanta = quanta;
}

bool Mailer::isFull(){
	return _isFull;
}

void Mailer::setScheduler(int sc_num){

	switch (sc_num){

		case 1 :

			_scheduler = new RRscheduler(_quanta,_mailMapWork ,this);
			break;

		case 2 :

			_scheduler = new MLscheduler(_quanta,_mailMapWork ,this);
			break;

		case 3 :

			_scheduler = new SRTFscheduler(_mailMapWork ,this);
			break;

		default : perror("Not an available scheduler number");

	}

}


map<string, Worker>* Mailer::getWorkers(){
	return _mailMapWork;
}

